using System.Collections.Generic;
using LiteNetLib;
using System.Net;
using System.Net.Sockets;
using System;
using System.IO;
using System.Linq;
using System.Text;
using LiteNetLib.Utils;
using Newtonsoft.Json.Linq;

namespace PvpServer
{
    public enum ConstVariable
    {
        HostConnected = 10,
        ClientConnected = 11,
        ClientConnectConfirm = 12,
        Data = 13,
        Disconnect = 14,
    }

    public class RoomService
    {
        string RoomUri = "";
        private int _disconnectTimeout = 5000;

        public static RoomService Instance { get; private set; }


        public void StartService(string roomUri)
        {
            RoomUri = roomUri;
            Instance = this;
        }

        public void StopService()
        {
            foreach (var room in Rooms)
            {
                room.Stop();
            }
        }

        public List<Room> Rooms = new List<Room>();

        public (Room, bool) GetRoom(int maxPlayer)
        {
            // 查找不满员且最大玩家数相同的房间
            foreach (var room in Rooms)
            {
                if (room.MatchPlayers.Count < room.MaxPlayerCount && room.MaxPlayerCount == maxPlayer && !room.Gaming)
                {
                    if (room.MatchPlayers.Count == 0)
                    {
                        Logger.Log("找到空房间");
                        room.Clear();
                        return (room, true);
                    }

                    return (room, false);
                }
            }

            // 所有房间都满员或没有匹配的最大玩家数，创建一个新房间
            // 创建并启动NetManager
            EventBasedNetListener listener = new EventBasedNetListener();
            NetManager netManager = new NetManager(listener);
            netManager.DisconnectTimeout = _disconnectTimeout;

            netManager.Start();

            // 获取分配的端口号
            int port = netManager.LocalPort;
            Logger.Log($"New room started on port {port}");

            // 创建房间实例
            Room newRoom = new Room
            {
                RoomNum = System.Guid.NewGuid().ToString(), // 生成唯一的UUID
                Uri = RoomUri,
                Port = port.ToString(),
                MaxPlayerCount = maxPlayer,
                Players = new List<NetPeer>(),
                NetManager = netManager,
                Host = null,
                Gaming = false
            };

            listener.ConnectionRequestEvent += request => { request.Accept(); };
            // 设置监听器事件处理
            listener.PeerConnectedEvent += peer => newRoom.OnPeerConnected(peer);
            listener.PeerDisconnectedEvent += (peer, info) => newRoom.OnPeerDisconnected(peer, info);
            listener.NetworkReceiveEvent += (peer, reader, channel, method) =>
                newRoom.OnNetworkReceive(peer, reader, channel, method);

            // 启动房间更新循环
            StartRoomUpdateLoop(newRoom);

            Rooms.Add(newRoom);
            return (newRoom, true);
        }

        // 添加一个方法来处理房间的网络更新
        private void StartRoomUpdateLoop(Room room)
        {
            // 创建一个新线程来运行网络更新循环
            new System.Threading.Thread(() =>
            {
                while (room.NetManager.IsRunning)
                {
                    room.NetManager.PollEvents(); // 处理网络事件
                    System.Threading.Thread.Sleep(10); // 15毫秒间隔，约等于66FPS
                }
            })
            {
                IsBackground = true // 设置为后台线程，这样主程序结束时它会自动终止
            }.Start();
        }
        
        public Room GetRoomByRoomNum(string roomNum)
        {
            foreach (var room in Rooms)
            {
                if (room.RoomNum == roomNum)
                    return room;
            }

            return null;
        }

        public Room GetRoomByPlayerUID(string playerUID)
        {
            foreach (var room in Rooms)
            {
                if (room.MatchPlayers.Contains(playerUID))
                {
                    return room;
                }
            }

            return null;
        }

        public class Room
        {
            public bool Gaming = false;
            public string RoomNum; // UUID作为房间的唯一标识符
            public string Uri;
            public string Port;
            public int MaxPlayerCount;
            public List<NetPeer> Players;
            public NetManager NetManager; // 持有NetManager的引用
            public bool HostReady => Host != null;
            public NetPeer Host;
            public ulong HostClientId;
            public Dictionary<ulong, NetPeer> Clients = new Dictionary<ulong, NetPeer>();

            private Queue<BinaryReader> readerPool = new Queue<BinaryReader>();
            private Queue<BinaryWriter> writerPool = new Queue<BinaryWriter>();

            public HashSet<string> MatchPlayers = new HashSet<string>();
            
            public string RoomOwnerUID;
            
            public bool MatchFinished => MatchPlayers.Count == MaxPlayerCount;

            public void RemoveMatchPlayer(string playerUID)
            {
                MatchPlayers.Remove(playerUID);
                
                if(MatchPlayers.Count == 0)
                {
                    RoomOwnerUID = string.Empty;
                }
                else
                {
                    //随机选择一个匹配玩家作为房间的所有者
                    foreach (var player in MatchPlayers)
                    {
                        if (player != playerUID)
                        {
                            RoomOwnerUID = player;
                            break;
                        }
                    }
                }
            }

            public void AddMatchPlayer(string playerUID)
            {
                if (string.IsNullOrEmpty(playerUID))
                {
                    return;
                }

                MatchPlayers.Add(playerUID);
                
                //第一个匹配玩家就是房间的所有者
                if (MatchPlayers.Count == 1)
                {
                    RoomOwnerUID = playerUID;
                }
            }

            BinaryReader GetBinaryReader()
            {
                if (readerPool.Count > 0)
                {
                    return readerPool.Dequeue();
                }

                return new BinaryReader(new MemoryStream());
            }

            BinaryWriter GetBinaryWriter()
            {
                if (writerPool.Count > 0)
                {
                    return writerPool.Dequeue();
                }

                return new BinaryWriter(new MemoryStream());
            }

            void ReturnBinaryReader(BinaryReader reader)
            {
                reader.BaseStream.SetLength(0);
                reader.BaseStream.Position = 0;
                readerPool.Enqueue(reader);
            }

            void ReturnBinaryWriter(BinaryWriter writer)
            {
                writer.BaseStream.SetLength(0);
                writer.BaseStream.Position = 0;
                writerPool.Enqueue(writer);
            }

            public void Clear()
            {
                Host = null;
                HostClientId = 0;
                Gaming = false;
                RoomOwnerUID = string.Empty;
                MatchPlayers.Clear();
                Players.Clear();
            }

            public void OnPeerConnected(NetPeer peer)
            {
                Logger.Log($"Player connected: {peer}");
                // 这里可以添加更多的连接处理逻辑
                Players.Add(peer);
            }

            public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
            {
                Logger.Log($"Player disconnected: {peer}, reason: {disconnectInfo.Reason}");
                // 这里可以处理玩家断开连接的逻辑
                Players.Remove(peer);
                var peerClientId = 0ul;
                var find = false;
                foreach (var pair in Clients)
                {
                    if (pair.Value.Equals(peer))
                    {
                        peerClientId = pair.Key;
                        find = true;
                        break;
                    }
                }

                if (find)
                {
                    var peerStr = peer.ToString();

                    if (peer.Equals(Host))
                    {
                        //host断开连接,通知所有客户端
                        Logger.Log($"host断开连接：{peerStr},通知所有客户端");
                        var keys = Clients.Keys.ToArray();
                        foreach (var key in keys)
                        {
                            var clientId = key;
                            if (clientId != peerClientId)
                            {
                                BinaryWriter binaryWriter = GetBinaryWriter();
                                binaryWriter.Write((byte)ConstVariable.Disconnect);
                                binaryWriter.Write(clientId);
                                binaryWriter.Write(HostClientId);
                                var memoryStream = (MemoryStream)binaryWriter.BaseStream;
                                var fullData = memoryStream.ToArray();
                                ReturnBinaryWriter(binaryWriter);
                                var targetPeer = Clients[clientId];
                                try
                                {
                                    Send(fullData, targetPeer);
                                }
                                catch (Exception e)
                                {
                                    Console.WriteLine(e);
                                }
                            }
                        }
                    }
                    else
                    {
                        //是客户端，通知host
                        if (Host != null)
                        {
                            Logger.Log($"客户端断开连接：{peerStr},通知host");
                            BinaryWriter binaryWriter = GetBinaryWriter();
                            binaryWriter.Write((byte)ConstVariable.Disconnect);
                            binaryWriter.Write(HostClientId);
                            binaryWriter.Write(peerClientId);
                            var memoryStream = (MemoryStream)binaryWriter.BaseStream;
                            var fullData = memoryStream.ToArray();
                            ReturnBinaryWriter(binaryWriter);
                            try
                            {
                                Send(fullData, Host);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e);
                            }
                        }
                    }
                }

                if (Players.Count == 0)
                {
                    Clear();
                }
            }


            public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channel,
                DeliveryMethod deliveryMethod)
            {
                var regionBytes = reader.GetRemainingBytes();
                var bytes = Lz4Helper.DecompressWithLength(regionBytes);
                var binaryReader = GetBinaryReader();
                binaryReader.BaseStream.Write(bytes, 0, bytes.Length);
                binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
                reader.Recycle();

                var key = binaryReader.ReadByte();

                if (key == (byte)ConstVariable.HostConnected)
                {
                    Host = peer;
                    var clientId = binaryReader.ReadUInt64();
                    HostClientId = clientId;
                    Clients[clientId] = peer;
                    Logger.Log($"房间已连接主机：{peer}");
                }
                else if (key == (byte)ConstVariable.ClientConnected)
                {
                    //通知host有客户端连接
                    Logger.Log($"房间已连接客户端：{peer}");
                    var binaryWriter = GetBinaryWriter();
                    binaryWriter.Write((byte)ConstVariable.ClientConnected);
                    binaryWriter.Write(peer.ToString());
                    var memStream = (MemoryStream)binaryWriter.BaseStream;
                    var fullData = memStream.ToArray();
                    ReturnBinaryWriter(binaryWriter);
                    Send(fullData, Host);
                }
                else if (key == (byte)ConstVariable.ClientConnectConfirm)
                {
                    //通知客户端连接成功
                    Logger.Log($"host确认连接");
                    var clientId = binaryReader.ReadUInt64();
                    var clientPeerStr = binaryReader.ReadString();
                    NetPeer clientPeer = null;
                    foreach (var player in Players)
                    {
                        if (player.ToString() == clientPeerStr)
                        {
                            clientPeer = player;
                            break;
                        }
                    }

                    Clients[clientId] = clientPeer;
                    if (clientPeer != null)
                    {
                        SendZiped(regionBytes, clientPeer);
                    }
                }
                else if (key == (byte)ConstVariable.Data)
                {
                    var targetId = binaryReader.ReadUInt64();
                    if (Clients.ContainsKey(targetId))
                    {
                        var targetPeer = Clients[targetId];
                        SendZiped(regionBytes, targetPeer);
                    }
                }
                else if (key == (byte)ConstVariable.Disconnect)
                {
                    var targetId = binaryReader.ReadUInt64();
                    if (Clients.ContainsKey(targetId))
                    {
                        var targetPeer = Clients[targetId];
                        SendZiped(regionBytes, targetPeer);
                    }
                }

                ReturnBinaryReader(binaryReader);
            }

            void SendZiped(byte[] bytes, NetPeer peer)
            {
                if(peer == null)
                    return;
                peer.Send(bytes, DeliveryMethod.ReliableOrdered);
            }

            void Send(byte[] bytes, NetPeer peer)
            {
                if(peer == null)
                    return;
                var zipBytes = Lz4Helper.CompressWithLength(bytes);
                peer.Send(zipBytes, DeliveryMethod.ReliableOrdered);
            }

            public void Stop()
            {
                if (NetManager != null)
                {
                    foreach (var binaryReader in readerPool)
                    {
                        binaryReader.Close();
                    }

                    readerPool.Clear();

                    foreach (var binaryWriter in writerPool)
                    {
                        binaryWriter.Close();
                    }

                    writerPool.Clear();
                    NetManager.Stop();
                    Logger.Log($"Room on port {Port} stopped");
                }
            }
        }
    }
}